<template>
  <div class="max-tabs">
    <div class="tab-head">
      <div class="tab-top">
        <div v-for="option in options"
             :class="{'tab-option-selected':currentKey === option[defaultFieldNames.key]}"
             class="tab-option"
             @click.stop="selected(option)">
          {{ option[defaultFieldNames.title] }}
          <span v-if="option[defaultFieldNames.closable]"
                class="close-button"
                @click.stop="close(option)">x</span>
        </div>
      </div>
    </div>
    <div class="tab-body">
      <transition-group tag="components" name="slide">
        <div v-for="(option, index) in currentOptions" :key="index">
          <component v-show="currentKey === option[defaultFieldNames.key]"
                     :is="option[defaultFieldNames.component]"/>
        </div>
      </transition-group>
    </div>
  </div>
</template>

<script>
import {defineComponent, ref, reactive, watch} from 'vue';

export default defineComponent({
  name: "max-tabs",
  setup(props, context) {
    /**
     * 变量列表：
     * defaultFieldNames：默认参数名称
     * currentKey：当前页面编号
     * currentOptions：当前页面列表
     */
    const defaultFieldNames = reactive({
      key: 'key',
      title: 'title',
      component: 'component',
      closable: 'closable'
    });
    const currentOptions = reactive([]);
    /**
     * 方法列表：
     * init：初始化
     * currentOption：激活绑定页面
     * selected：激活选中页面
     * singleHandler：单例模式处理器
     * multipleHandler：多例模式处理器
     * close：关闭选中页面
     */
    const init = () => {
      Object.assign(defaultFieldNames, props.fieldNames);
      currentOption(props.currentKey);
    }

    const currentOption = (key) => {
      let find = props.options.find(option => option[defaultFieldNames.key] === key);
      if (find) selectHandler(find);
    }

    const selected = (option) => {
      context.emit("update:currentKey", option[defaultFieldNames.key]);
      context.emit('selected', option);
    }

    const selectHandler = (option) => {
      if (props.mode === 'single') singleHandler(option);
      if (props.mode === 'multiple') multipleHandler(option);
    }

    const singleHandler = (option) => {
      currentOptions.length = 0;
      currentOptions.push(option);
    }

    const multipleHandler = (option) => {
      let find = currentOptions.find(currentOption =>
          currentOption[defaultFieldNames.key] === option[defaultFieldNames.key]);
      if (!find) currentOptions.push(option);
    }

    const close = (option) => {
      let key = option[defaultFieldNames.key];
      removeCurrentOptions(key);
      removeOptions(key);
      context.emit('close', option);
    }

    const removeCurrentOptions = (key) => {
      let result = currentOptions.filter(currentOption =>
          currentOption[defaultFieldNames.key] !== key);
      currentOptions.length = 0;
      currentOptions.push(...result);
    }

    const removeOptions = (key) => {
      context.emit("update:options", props.options.filter(option =>
          option[defaultFieldNames.key] !== key));
    }

    watch(() => props.currentKey, (newVal, oldVal) => {
      currentOption(newVal);
    });

    init();
    return {
      defaultFieldNames,
      currentOptions,
      selected,
      close
    }
  },
  props: {
    fieldNames: {
      type: Object,
      default: {}
    },
    mode: {
      type: String,
      default: 'multiple'
    },
    options: {
      type: Array,
      default: []
    },
    currentKey: {
      type: String,
      default: null
    }
  },
});
</script>
<style scoped>
.max-tabs {
  overflow: hidden;
  transition: all .3s cubic-bezier(.645, .045, .355, 1);
}

.tab-head {
  border-bottom: 1px solid #f0f0f0;
  outline: none;
}

.tab-top {
  margin-bottom: -1px;
  white-space: nowrap;
}

.tab-option {
  position: relative;
  display: inline-block;
  box-sizing: border-box;
  cursor: pointer;
  height: 40px;
  margin: 0 2px 0 0;
  padding: 0 16px;
  line-height: 38px;
  font-size: 14px;
  background: #fafafa;
  border: 1px solid #f0f0f0;
  border-radius: 2px 2px 0 0;
}

.tab-option-selected {
  color: #1890ff;
  background: #fff;
  border-color: #f0f0f0;
  border-bottom: 1px solid #fff;
}

.close-button {
  margin-left: 3px;
  overflow: hidden;
  color: #00000073;
}

.tab-option:hover,
.tab-option:focus {
  color: #47a0ff;
}

.close-button:hover,
.close-button:focus {
  color: #000;
}

.tab-body {
  margin: 16px;
}

</style>
